''' <summary>
''' This is a tab page control which behaves kinda like IE's.
''' </summary>
''' <remarks></remarks>
<System.ComponentModel.Description("A tab control simlar to IE 7's."), System.Drawing.ToolboxBitmap(GetType(Windows.Forms.TabControl))> _
 Public Class PageCollection : Inherits FlickerFreeControl : Implements IList(Of TabPage)

#Region "Events"
    ''' <summary>
    ''' Indicates that the specified page has been added.
    ''' </summary>
    ''' <param name="page">The page which has been added.</param>
    Public Event PageAdded(ByVal page As TabPage)

    ''' <summary>
    ''' Indicates that the specified page has been removed.
    ''' </summary>
    ''' <param name="page">The page which was removed.</param>
    Public Event PageRemoved(ByVal page As TabPage)

    ''' <summary>
    ''' Indicates that the currently selected page has changed.
    ''' </summary>
    ''' <param name="currentPage">The currently selected page.</param>
    ''' <param name="previousPage">The previously selected page.</param>
    Public Event CurrentPageChanged(ByVal currentPage As TabPage, ByVal previousPage As TabPage)

    ''' <summary>
    ''' Indicates that the specified page is closing.  This is raised before the page is
    ''' closed and removed.  Setting cancel to true will prevent the page from being removed.
    ''' </summary>
    Public Event PageClosing(ByVal page As TabPage, ByRef cancel As Boolean)


    Private Sub OnPageAdded(ByVal page As TabPage)
        If (Me.CurrentPage Is Nothing) Then Me.CurrentPage = page
        RaiseEvent PageAdded(page)
    End Sub

    Private Sub OnPageRemoved(ByVal page As TabPage, ByVal index As Integer)
        If (page Is Me.CurrentPage) Then
            If (index >= Count) Then index = Count - 1
            If (index >= 0) Then
                CurrentPage = Item(index)
            Else
                CurrentPage = Nothing
            End If
        End If

        RaiseEvent PageRemoved(page)
    End Sub

    Protected Sub OnPageClosing(ByVal page As TabPage)
        Dim cancel As Boolean = False
        RaiseEvent PageClosing(page, cancel)
        If (cancel) Then Exit Sub
        Me.Remove(page)
    End Sub
#End Region

#Region "Fields"
    Private myPages As New List(Of TabPage)
    Private PageContainer As New PagePanel(Me)
    Friend ToolTips As New ToolTip()
    Private myTabView As New TabView(Me)
#End Region

#Region "Properties"
    Private myTopMargin As Integer = 3
    ''' <summary>
    ''' TopMargin specifies the height difference between the active tab and the non-active tabs.
    ''' </summary>
    ''' <value>An integer representing the height difference.</value>
    <System.ComponentModel.Description("Specifies the height difference between the active tab and the non-active tabs."), _
        System.ComponentModel.Category("Appearance")> _
    Public Property TopMargin() As Integer
        Get
            Return myTopMargin
        End Get
        Set(ByVal value As Integer)
            myTopMargin = value
            Me.myTabView.Invalidate()
        End Set
    End Property

    Private myCurrentPage As TabPage = Nothing
    ''' <summary>
    ''' Sets the current/active tab page.
    ''' </summary>
    Public Property CurrentPage() As TabPage
        Get
            Return myCurrentPage
        End Get
        Set(ByVal value As TabPage)
            If (value Is myCurrentPage) Then Exit Property
            Dim previousPage As TabPage = myCurrentPage
            myCurrentPage = value
            RaiseEvent CurrentPageChanged(myCurrentPage, previousPage)
        End Set
    End Property

    Private myTabColor As Color = Color.LightSteelBlue
    ''' <summary>
    ''' Gets or sets the color used to calculate the gradient for the tabs.
    ''' </summary>
    <System.ComponentModel.Browsable(True), _
            System.ComponentModel.Category("Appearance"), _
            System.ComponentModel.Description("Gets or sets the color used to calculate the gradient for the tabs.")> _
        Public Property TabColor() As Color
        Get
            Return myTabColor
        End Get
        Set(ByVal value As Color)
            myTabColor = value
        End Set
    End Property
#End Region

#Region "IList Implementation"
    Public Sub Add(ByVal item As TabPage) Implements System.Collections.Generic.ICollection(Of TabPage).Add
        myPages.Add(item)
        OnPageAdded(item)
    End Sub

    Public Sub Clear() Implements System.Collections.Generic.ICollection(Of TabPage).Clear
        For i As Integer = 0 To myPages.Count - 1
            ' We don't want to call OnPageRemoved, since this is a clear.
            RaiseEvent PageRemoved(myPages(i))
        Next
        myPages.Clear()
    End Sub

    Public Overloads Function Contains(ByVal item As TabPage) As Boolean Implements System.Collections.Generic.ICollection(Of TabPage).Contains
        Return myPages.Contains(item)
    End Function

    Public Sub CopyTo(ByVal array() As TabPage, ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of TabPage).CopyTo
        myPages.CopyTo(array, arrayIndex)
    End Sub

    Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of TabPage).Count
        Get
            Return myPages.Count
        End Get
    End Property

    Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of TabPage).IsReadOnly
        Get
            Return True
        End Get
    End Property

    Public Function Remove(ByVal item As TabPage) As Boolean Implements System.Collections.Generic.ICollection(Of TabPage).Remove
        RemoveAt(myPages.IndexOf(item))
    End Function

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of TabPage) Implements System.Collections.Generic.IEnumerable(Of TabPage).GetEnumerator
        Return myPages.GetEnumerator()
    End Function

    Public Function IndexOf(ByVal item As TabPage) As Integer Implements System.Collections.Generic.IList(Of TabPage).IndexOf
        Return myPages.IndexOf(item)
    End Function

    Public Sub Insert(ByVal index As Integer, ByVal item As TabPage) Implements System.Collections.Generic.IList(Of TabPage).Insert
        myPages.Insert(index, item)
        OnPageAdded(item)
    End Sub

    Default Public Property Item(ByVal index As Integer) As TabPage Implements System.Collections.Generic.IList(Of TabPage).Item
        Get
            Return myPages.Item(index)
        End Get
        Set(ByVal value As TabPage)
            Dim prevControl As TabPage = myPages.Item(index)
            If (prevControl IsNot value) Then
                myPages.Item(index) = value
                If (prevControl IsNot value AndAlso value IsNot Nothing) Then OnPageRemoved(prevControl, index)
                OnPageAdded(value)
            End If
        End Set
    End Property

    Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.Generic.IList(Of TabPage).RemoveAt
        If (index < 0) Then Exit Sub

        Dim page As TabPage = Item(index)
        myPages.RemoveAt(index)
        OnPageRemoved(page, index)
    End Sub

    Public Function GetNonGenericEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return DirectCast(myPages, IEnumerable).GetEnumerator()
    End Function
#End Region

#Region "Event Handling"
    Private Sub TabPages_CurrentPageChanged(ByVal currentPage As TabPage, ByVal previousPage As TabPage) Handles Me.CurrentPageChanged
        Me.SuspendPainting = True
        Me.PageContainer.Controls.Clear()
        If (currentPage IsNot Nothing) Then
            currentPage.Control.Dock = DockStyle.Fill
            currentPage.Control.Visible = True
            Me.PageContainer.Controls.Add(currentPage.Control)
        End If
        Me.SuspendPainting = False
    End Sub

    Private Sub PageCollection_FontChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.FontChanged
        Me.myTabView.Height = Me.Font.Height + 8
    End Sub

    ' Set the page's parent.
    Private Sub TabPages_PageAdded(ByVal page As TabPage) Handles Me.PageAdded
        page.SetParent(Me)
        AddHandler page.TabPageCtl.OnClose, AddressOf OnPageClosing
    End Sub

    ' Unset the page's parent.
    Private Sub TabPages_PageRemoved(ByVal page As TabPage) Handles Me.PageRemoved
        If (Me.PageContainer.Contains(page.Control)) Then Me.PageContainer.Controls.Clear()
        page.SetParent(Nothing)
        RemoveHandler page.TabPageCtl.OnClose, AddressOf OnPageClosing
    End Sub
#End Region

#Region "Page Panel"
    ''' <summary>
    ''' The container for the page/control belonging to the current tab.
    ''' </summary>
    Private Class PagePanel
        Inherits Panel

        Private Pages As PageCollection

        Public Sub New(ByVal pages As PageCollection)
            Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            Me.SetStyle(ControlStyles.UserPaint, True)
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
            Me.Pages = pages
            Me.Dock = DockStyle.Fill
            Me.Padding = New Padding(1, 0, 1, 1)
            Me.Pages.Controls.Add(Me)
            Me.BringToFront()
        End Sub

        Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            e.Graphics.Clear(Color.White)
            Using borderPen As Pen = TabBaseControl.GetBorderPen(Pages.TabColor)
                e.Graphics.DrawLine(borderPen, 0, 0, 0, Me.Height - 1)
                e.Graphics.DrawLine(borderPen, 0, Me.Height - 1, Me.Width - 1, Me.Height - 1)
                e.Graphics.DrawLine(borderPen, Me.Width - 1, 0, Me.Width - 1, Me.Height - 1)
            End Using
        End Sub
    End Class
#End Region

End Class
